#include "MLProgressbar.h"
#include "ParticleTrack.h"

ParticleTrack::ParticleTrack(
	int frame_size_x, int frame_size_y,
	double frame_rate,
	VelocityStream& stream,
	Color color,
	Byte alpha,
	double brightness,
	Double2 lifespan_range,
	Location radius_range,
	Double2 v_range,
	Double2 a_delta_range,
	Double2 init_angle_range,
	Double2 a_angle_range,
	GLuint glsl,
	GLuint mix_glsl,
	double particles_sparseness,
	int record_radius
) {
	_frame_size_x = frame_size_x; _frame_size_y = frame_size_y;
	dt = 1.0 / frame_rate;
	_stream = stream;
	_lifespan_range = std::uniform_int_distribution<int>(lifespan_range.x, lifespan_range.y);
	_radius_range = std::uniform_int_distribution<int>(radius_range.x, radius_range.y);
	_v_range = std::uniform_real_distribution<double>(v_range.x, v_range.y);
	_a_delta_range = std::uniform_real_distribution<double>(a_delta_range.x, a_delta_range.y);
	_color = color;
	std::random_device rd;
	_random_engine.seed(rd());
	double need_to_put = 0;
	_particles_num_list = new size_t[stream.length];
	for (size_t i = 0; i < stream.length; i++) {
		need_to_put += stream.get(i) / particles_sparseness / frame_rate;
		_particles_num_list[i] = (size_t)floor(need_to_put);
		need_to_put -= floor(need_to_put);
	}
	max_particles = (size_t)(lifespan_range.y * frame_rate + radius_range.y + 1) * (size_t)ceil(256 / particles_sparseness / frame_rate); // 根据需求调整
	_particle_pool = new ParticleObj[max_particles];
	_p_system = Drawer::initParticles(
		glm::vec2((float)radius_range.x, (float)radius_range.y),
		glm::vec4((float)(color.x * brightness), (float)(color.y * brightness), (float)(color.z * brightness), (float)alpha),
		glm::vec2((float)lifespan_range.x * frame_rate, (float)lifespan_range.y * frame_rate),
		record_radius,
		glm::vec2((float)v_range.x / frame_rate, (float)v_range.y / frame_rate),
		glm::vec2((float)init_angle_range.x, (float)init_angle_range.y),
		glm::vec2((float)a_delta_range.x / frame_rate, (float)a_delta_range.y / frame_rate),
		glm::vec2((float)a_angle_range.x / frame_rate, (float)a_angle_range.y / frame_rate),
		max_particles,
		(float)_frame_size_x,
		(float)_frame_size_y,
		(float)frame_rate
	);
	size_t count = 0;
	_glsl = glsl;
	_mix_glsl = mix_glsl;
}

void ParticleTrack::clear() {
	delete _particle_pool;
	delete _particles_num_list;
	_stream.clear();
}

void ParticleTrack::get_frame(size_t frame_index, MLFrame& frame) {
	double particles_num = _particles_num_list[frame_index];
	_draw_particle(particles_num, frame);
	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
		throw "";
	}
}

void ParticleTrack::_allocate_particles(int count) {
	size_t i = 0;
	while (count > 0) {
		if (_particle_pool[i]._radius > 0) {
			i++;
			continue;
		};
		_particle_pool[i]._x = { (double)_frame_size_x / 2, (double)_frame_size_y / 2 };
		_particle_pool[i]._lifespan = _lifespan_range(_random_engine);
		_particle_pool[i]._radius = _radius_range(_random_engine);
		_particle_pool[i]._v = { _v_range(_random_engine), _v_range(_random_engine) };
		_particle_pool[i]._a = { _a_delta_range(_random_engine), _a_delta_range(_random_engine) };
		_particle_pool[i]._is_active = true;
		i++;
		count--;
	}
}

void ParticleTrack::_draw_particle(size_t particles_num, MLFrame& frame) {
	Utils::clearFrame(_p_system.msaaFBO);
	Drawer::updateAndDrawParticles(_glsl, _p_system, particles_num);
	frame.mix(_p_system.FBO, _p_system.resolveTexture, 0, _mix_glsl);
}
